using System;
using System.Web;
using System.Configuration;
using System.Web.SessionState;

namespace GoodStuff.Web
{
	/// <summary>
    /// When this HttpModule is registered, all visitors will be redirected to the configured 'under construction page'. 
    /// Through configuration you can set IP-addresses that will be excluded and thus won't be redirected (so they still or yet can use the application).
	/// </summary>
	/// <remarks>
    /// 'SiteUnderConstructionAllowIPs' contains a comma-separated list of IP addresses that are allowed to browse the website. You can use
    /// 129.0.0.0/24 notation to include subnetmasks (CIDR notation).
    /// If the client is not allowed to view a page, 'SiteUnderConstructionRedirect' contains an URL that the client is redirected to.
    /// WARNING: If SiteUnderConstructionRedirect is also an ASPX page, an endless loop may occur. We suggest using a non-.net mapped
	/// page, such as .htm.
    /// When your application is NOT under construction, unregister (comment) the module to prevent unnecessary overhead.
	/// </remarks>
	public class SiteUnderConstructionModule : IHttpModule
	{
        private SiteUnderConstructionConfiguration _config;

		public void Init(HttpApplication context)
		{
            //The init will be fired only after the application has been recycled. A good possibility to check if 
            //a valid configuration is present.

            _config = SiteUnderConstructionConfigurationSectionHandler.GetConfiguration("goodStuff/siteUnderConstructionConfiguration");
            if (_config == null)
            {
                throw new ConfigurationErrorsException("The SiteUnderConstructionModule has been configured, but no configuration is configured. Specify a <goodStuff> <siteUnderConstructionConfiguration> element.");
            }
            else if (string.IsNullOrEmpty(_config.UnderConstructionPageURL))
            {
                throw new ConfigurationErrorsException("SiteUnderConstruction-Module: a required attribute 'underConstructionPageURL' is not configured in the configuration. Please specify url of the underconstruction page to redirect to. Note:use a non asp.net mapped page like .htm, .html or a simple image. Configurationsection = goodStuff/siteUnderConstructionConfiguration");
            }
            
            //Inspect every incoming request.
			context.BeginRequest +=new EventHandler(context_BeginRequest);
		}

        /// <summary>
        /// Dispose
        /// </summary>
		public void Dispose()
		{
		}

		private void context_BeginRequest(object sender, EventArgs e)
		{
            try
            {
                //Check if the source (IP-address) of the request should be excluded from redirection.
                if (!string.IsNullOrEmpty(_config.IgnoreIPs) && GoodStuff.Net.IPUtility.VerifyIP(_config.IgnoreIPs) == false)
                {
                    string requestUrl = HttpContext.Current.Request.Url.AbsolutePath;
                    string redirectTo = _config.UnderConstructionPageURL;
                    if (redirectTo.StartsWith("~/"))      //VirtualPathUtility.IsAppRelative(redirect)
                    {
                        redirectTo = VirtualPathUtility.ToAbsolute(redirectTo);
                    }

                    //redirect only when the redirectpage isn't the same as the current page
                    //can happen when redirectpage is also mapped to .Net (although it's not advised to do so)
                    if (string.Compare(redirectTo, requestUrl, true) != 0)
                    {
                        HttpContext.Current.Response.Redirect(redirectTo);
                        HttpContext.Current.Response.End();
                    }
                }
            }
            catch (ConfigurationErrorsException)
            {
                throw;
            }
            catch (FormatException)
            {
                throw; //probably wrong IPaddress entered.
            }
            catch (Exception)
            {
                HttpContext.Current.Response.Write("<H1>Site is under construction</h1>");
                HttpContext.Current.Response.End();
            }
		}
	}
}
